﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using System.IO;

namespace Spelprojekt.Model
{
    public class Map
    {
        public int m_level = 0;

        public string m_name = "";

        public static int g_width = 0;
        public static int g_height = 0;               

        public Game m_game;

        public Tile[,] m_tiles;        
                
        public Map(ref Player a_player)
        {
            LoadLevel(1, ref a_player);
        }

        public Map(int a_level, ref Player a_player)
        {
            LoadLevel(a_level, ref a_player);
        }

        public void LoadLevel(int a_level, ref Player a_player)
        {
            //sets the level number
            m_level = a_level;

            //creates a filepath to the level
            string levelFilePath = String.Format("Levels/level_{0}.txt", a_level);

            try
            {
                //gets the level file
                string[] levelData = File.ReadAllLines(levelFilePath);

                for (int i = 0; i < levelData.Length; i++)
                {
                    if (levelData[i] == "Name")
                    {
                        //next line
                        i++;

                        //read line
                        m_name = levelData[i];

                        //if we want to use a standard (explained above LoadLevel())
                        //next line
                        //i++;
                    }
                    else if (levelData[i] == "Map")
                    {
                        //next line
                        i++;

                        //sets the maps width and height
                        g_width = Int32.Parse(GetData(levelData[i], 0));
                        g_height = Int32.Parse(GetData(levelData[i], 1));

                        //create the tiles
                        m_tiles = new Tile[g_width, g_height];

                        //next line
                        i++;

                        //initialize all tiles
                        for (int x = 0; x < g_width; x++)
                        {
                            for (int y = 0; y < g_height; y++)
                            {
                                m_tiles[x, y] = new Tile();
                            }
                        }

                        //sets the tiles
                        for (int y = 0; y < g_height; y++)
                        {
                            for (int x = 0; x < g_width; x++)
                            {
                                //sets the tile depending on what char it is
                                //there is no need to set Free tiles since they are initialized as them
                                if (levelData[i + y][x] == 'O')
                                {
                                    m_tiles[x, y].m_tileType = Tile.TileType.Blocked;
                                }                                
                                else if (levelData[i + y][x] == 'Y')
                                {
                                    m_tiles[x, y].m_tileType = Tile.TileType.Exit;
                                }                                
                                else if (levelData[i + y][x] == 'X')
                                {
                                    m_tiles[x, y].m_tileType = Tile.TileType.Deadly;
                                }                                
                            }
                        }

                        //if we want to use a standard (explained above LoadLevel())
                        //skip the map data (on the level file)
                        //i += g_height;
                    }                    
                    /*else if (levelData[i] == "Enemy")
                    {
                        //next line
                        i++;

                        //sets the number of blobs
                        m_numberOfEnemies = Int32.Parse(levelData[i]);

                        //create the blobs
                        m_game.m_enemies = new Enemy[m_numberOfEnemies];

                        //next line
                        i++;

                        for (int x = 0; x < m_numberOfEnemies; x++)
                        {
                            m_game.m_enemies[x] = new Enemy(new Vector2(float.Parse(GetData(levelData[i + x], 0)),
                                                              float.Parse(GetData(levelData[i + x], 1))));
                        }

                        //if we want to use a standard (explained above LoadLevel())
                        //next line
                        //i += m_numberOfBlobs; 
                    }*/
                }
            }
            catch (Exception e)
            {
                // Let the user know what went wrong.
                Console.WriteLine("LoadLevel ERROR: ");
                Console.WriteLine(e.Message);
            }

        }

        public bool IsCollidingWithDeadlyBlock(Vector2 a_pos, float a_diameter)
        {
            Vector2 topLeft = new Vector2(a_pos.X - a_diameter / 2.0f, a_pos.Y - a_diameter / 2.0f);
            Vector2 bottomRight = new Vector2(a_pos.X + a_diameter / 2.0f, a_pos.Y + a_diameter / 2.0f);

            /*Vector2 topLeft = new Vector2(a_pos.X - a_diameter.X / 2.0f, a_pos.Y - a_diameter.Y);
            Vector2 bottomRight = new Vector2(a_pos.X + a_diameter.X / 2.0f, a_pos.Y);*/


            for (int x = 0; x < g_width; x++)
            {
                for (int y = 0; y < g_height; y++)
                {

                    if (bottomRight.X < (float)x)
                        continue;
                    if (bottomRight.Y < (float)y)
                        continue;
                    if (topLeft.X > (float)x + 1.0f)
                        continue;
                    if (topLeft.Y > (float)y + 1.0f)
                        continue;

                    if (m_tiles[x, y].m_tileType == Tile.TileType.Deadly)
                    {
                        return true;
                    }
                }
            }


            return false;
        }

        public bool IsAtExit(Vector2 a_pos, Vector2 a_size, Tile.TileType a_type)
        {
            Vector2 topLeft = new Vector2(a_pos.X - a_size.X / 2.0f, a_pos.Y - a_size.Y);
            Vector2 bottomRight = new Vector2(a_pos.X + a_size.X / 2.0f, a_pos.Y);

            for (int x = 0; x < g_width; x++)
            {
                for (int y = 0; y < g_height; y++)
                {

                    if (bottomRight.X < (float)x)
                        continue;
                    if (bottomRight.Y < (float)y)
                        continue;
                    if (topLeft.X > (float)x + 1.0f)
                        continue;
                    if (topLeft.Y > (float)y + 1.0f)
                        continue;

                    if (m_tiles[x, y].m_tileType == a_type)
                    {
                        return true;
                    }
                }
            }

            return false;
        }        

        public bool IsInHole(Vector2 a_pos)
        {

            if(a_pos.Y > g_height + 3)
            {
                return true;
            }
            return false;
        }

        public bool IsCollidingWithCircle(Vector2 a_pos, float a_diameter, int a_x, int a_y)
        {
            Vector2 rect = new Vector2((float)a_x + 0.5f, (float)a_y + 0.5f);

            Vector2 circleDistance = new Vector2();

            circleDistance.X = Math.Abs(a_pos.X - rect.X);
            circleDistance.Y = Math.Abs(a_pos.Y - rect.Y);

            if (circleDistance.X > (0.5f + a_diameter / 2)) { return false; }
            if (circleDistance.Y > (0.5f + a_diameter / 2)) { return false; }

            if (circleDistance.X <= (0.5f)) { return true; }
            if (circleDistance.Y <= (0.5f)) { return true; }

            /*if (circleDistance.X <= (0.5f) && circleDistance.Y <= (0.5f)) { 
                return true; 
            }*/

            float cornerDistance_sq = (circleDistance.X - 0.5f) * (circleDistance.X - 0.5f) +
                                 (circleDistance.Y - 0.5f) * (circleDistance.Y - 0.5f);

            return (cornerDistance_sq <= (a_diameter / 2 * a_diameter / 2));

        }        

        public bool IsCollidingAt(Vector2 a_pos, Vector2 a_size, Tile.TileType a_type)
        {

            Vector2 topLeft = new Vector2(a_pos.X - a_size.X / 2.0f, a_pos.Y - a_size.Y);
            Vector2 bottomRight = new Vector2(a_pos.X + a_size.X / 2.0f, a_pos.Y);

            for (int x = 0; x < g_width; x++)
            {
                for (int y = 0; y < g_height; y++)
                {

                    if (bottomRight.X < (float)x)
                        continue;
                    if (bottomRight.Y < (float)y)
                        continue;
                    if (topLeft.X > (float)x + 1.0f)
                        continue;
                    if (topLeft.Y > (float)y + 1.0f)
                        continue;

                    if (m_tiles[x, y].m_tileType == a_type)
                    {
                        return true;
                    }
                }
            }

            return false;
        }       

        private string GetData(string a_line, int a_dataIndex)
        {
            //counts the ;
            int indexCounter = 0;

            string data = "";

            //makes the line end with a ;
            a_line += ";";

            for (int i = 0; i < a_line.Length; i++)
            {
                if (a_line[i] == ';')
                {
                    indexCounter++;

                    //to skip the ; and the space
                    i += 2;
                }

                //if this data has been requested
                if (a_dataIndex == indexCounter)
                {
                    for (int j = i; j < a_line.Length; j++)
                    {
                        //if the data has ended
                        if (a_line[j] == ';')
                        {
                            return data;
                        }

                        //get the char
                        data += a_line[j];
                    }
                }
            }

            //if no match was found
            return null;
        }
    }
}
